package org.wattdepot.cli.command;

import java.util.List;
import java.util.ArrayList;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.cli.processor.CommandLineInterface;
import org.wattdepot.client.MiscClientException;
import org.wattdepot.client.ResourceNotFoundException;
import org.wattdepot.resource.source.jaxb.Source;

/**
 * Generates the total power generated, in Watts, by all non-virtual sources associated with this
 * source that use the specified fuel type. This class extends CommandLineInterface to have access
 * to the WattDepotClient and implements WattDepotCliCommand interface to ensure this class does a
 * specific command.
 * 
 * @author Edward Meyer, Bao Huy Ung
 * 
 */
public class TotalPower extends CommandLineInterface implements WattDepotCliCommand {

  /**
   * Creates a TotalPower object to return power generated, in Watts, by all non-virtual sources
   * associated with this source that use the specified fuel type.
   */
  public TotalPower() {
    // Empty Constructor.
  }

  /**
   * Returns the total power generated, in Watts, by all non-virtual sources associated with this
   * source that use the specified fuel type.
   * 
   * @param args Is a list of all the arguments entered by the user.
   * @return The power generated, or an error message.
   */
  public String doCommand(List<String> args) {
    // If there are too few or too many arguments, return an error message.
    if (args.size() != 5) {
      return "Error: Incorrect number of arguments were entered. Expected 5, instead "
          + args.size() + " were entered.";
    }
    // Check is proper keyword "fuelType" was used in the command.
    if (!args.get(3).equalsIgnoreCase("fueltype")) {
      return "Error: Keyword \"fuelType\" was mistyped as \"" + args.get(3) + "\".";
    }

    String inputSourceName = args.get(1);
    String inputStamp = args.get(2);
    Source inputSource = null;
    String inputFuelType = args.get(4);
    Double totalPower = 0.0;
    XMLGregorianCalendar timeStamp = null;

    // Check if a valid source was entered.
    inputSource = isValidSource(inputSourceName);
    if (inputSource == null) {
      return "\"" + inputSourceName + "\" is not a valid source.";
    }

    // Check if a valid timestamp was entered.
    timeStamp = isValidTimestamp(inputStamp);
    if (timeStamp == null) {
      return "Timestamp: \"" + inputStamp + "\" cannot be parsed into a timestamp.";
    }

    // Create a list of non-virtual subsources for the given inputSource.
    List<Source> nonVirtuals = null;
    try {
      // If the source is virtual then it has non-virtual subsources.
      // Can only use non-virtual sources to calculate the total power.
      if (inputSource.isVirtual()) {
        nonVirtuals = getNonVirtuals(inputSource, new ArrayList<Source>());
      }
      else {
        // Else, the inputSource was a non-virtual source, create the list with only 1 element.
        nonVirtuals = new ArrayList<Source>();
        nonVirtuals.add(inputSource);
      }
    }
    // If anything goes wrong during the recursion process getNonVirtuals.
    catch (Exception e) {
      return "Error: Could not compile a list of all non-virtual subsources for source \""
          + inputSourceName + "\".\n" + e;
    }

    // Go through all the non-virtual sources and
    // add the total power generated given the fuel type.
    for (Source nonVirtualSub : nonVirtuals) {
      // Verify that the source uses the desired fuel type.
      if (nonVirtualSub.getProperty("fuelType").equalsIgnoreCase(inputFuelType)) {
        try {
          totalPower += client.getPowerGenerated(nonVirtualSub.getName(), timeStamp);
        }
        catch (ResourceNotFoundException r) {
          return "Source: \"" + nonVirtualSub.getName() + "\" contains no power generated data "
              + "on: \"" + inputStamp + "\".";
        }
        catch (MiscClientException e) {
          return "Network error occured while adding total power.";
        }
        catch (Exception e) {
          return "Unexpected error occured while adding total power. \n" + e;
        }
      }
    }

    if (totalPower == 0.0) {
      return "No power generated data found for non-virtual sources with fuel type: \""
          + inputFuelType + "\". \nPossible invalid fuel type used.";
    }

    return totalPower.toString();
  }

}
